import 'package:backend.core/core/domain/config/config.dart';
import 'package:backend.core/core/domain/helpers/does_ip_match_ip_or_subnet_mask.dart';
import 'package:backend.core/core/domain/helpers/issue_email_verification_code.dart';
import 'package:backend.core/core/domain/helpers/validate_email.dart';
import 'package:backend.core/core/domain/helpers/validate_password.dart';
import 'package:backend.core/core/domain/helpers/verify_access_token.dart';
import 'package:backend.core/core/domain/repositories/app_store_purchased_subscription_info_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/app_store_transaction_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/app_store_user_to_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/devices_to_app_store_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/devices_to_google_play_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/email_verification_code_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/google_play_purchased_item_info_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/google_play_transaction_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/google_play_user_to_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/user_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_payment_method_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_purchase_item_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_purchased_subscription_info_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_transaction_repository/repository.dart';
import 'package:backend.core/core/domain/services/access_token_service/service.dart';
import 'package:backend.core/core/domain/services/email_service/service.dart';
import 'package:backend.core/core/domain/services/password_service/service.dart';
import 'package:backend.core/core/infrastructure/middlewares/forbid_admin_authorization.dart';
import 'package:backend.core/core/infrastructure/middlewares/log_requests.dart';
import 'package:backend.core/core/infrastructure/middlewares/require_admin_authorization.dart';
import 'package:backend.core/core/infrastructure/middlewares/require_authorization.dart';
import 'package:backend.core/core/infrastructure/middlewares/require_end_user_authorization.dart';
import 'package:backend.core/core/infrastructure/repositories/app_store_purchased_subscription_info_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/app_store_transaction_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/app_store_user_to_user_link_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/devices_to_app_store_user_link_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/devices_to_google_play_user_link_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/email_verification_code_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/google_play_purchased_item_info_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/google_play_transaction_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/google_play_user_to_user_link_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/user_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/web_payment_method_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/web_purchase_item_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/web_purchased_subscription_info_repository/repository.dart';
import 'package:backend.core/core/infrastructure/repositories/web_transaction_repository/repository.dart';
import 'package:backend.core/core/infrastructure/services/access_token_service/service.dart';
import 'package:backend.core/core/infrastructure/services/email_service/service.dart';
import 'package:backend.core/core/infrastructure/services/password_service/service.dart';
import 'package:get_it/get_it.dart';
import 'package:mongo_dart/mongo_dart.dart';

final sl = GetIt.asNewInstance();

Future<void> init() async {
  // db

  final dbHost = Config().mongodbHost;
  final dbPort = Config().mongodbPort;
  final dbName = Config().mongodbDbName;

  final db = Db('mongodb://$dbHost:$dbPort/$dbName');

  sl.registerSingleton(db);

  // domain helpers

  sl.registerLazySingleton<DoesIPMatchIPOrSubnetMask>(() {
    return const DoesIPMatchIPOrSubnetMaskImpl();
  });

  sl.registerLazySingleton<IssueEmailVerificationCode>(() {
    return const IssueEmailVerificationCodeImpl();
  });

  sl.registerLazySingleton<ValidateEmail>(() {
    return const ValidateEmailImpl();
  });

  sl.registerLazySingleton<ValidatePassword>(() {
    return const ValidatePasswordImpl();
  });

  sl.registerLazySingleton<VerifyAccessToken>(() {
    return VerifyAccessTokenImpl(
      accessTokenService: sl(),
    );
  });

  // repositories

  sl.registerLazySingleton<AppStorePurchasedSubscriptionInfoRepository>(() {
    return AppStorePurchasedSubscriptionInfoRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<AppStoreTransactionRepository>(() {
    return AppStoreTransactionRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<AppStoreUserToUserLinkRepository>(() {
    return AppStoreUserToUserLinkRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<DevicesToAppStoreUserLinkRepository>(() {
    return DevicesToAppStoreUserLinkRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<DevicesToGooglePlayUserLinkRepository>(() {
    return DevicesToGooglePlayUserLinkRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<EmailVerificationCodeRepository>(() {
    return EmailVerificationCodeRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<GooglePlayPurchasedItemInfoRepository>(() {
    return GooglePlayPurchasedItemInfoRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<GooglePlayTransactionRepository>(() {
    return GooglePlayTransactionRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<GooglePlayUserToUserLinkRepository>(() {
    return GooglePlayUserToUserLinkRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<UserRepository>(() {
    return UserRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<WebPaymentMethodRepository>(() {
    return WebPaymentMethodRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<WebPurchaseItemRepository>(() {
    return WebPurchaseItemRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<WebPurchasedSubscriptionInfoRepository>(() {
    return WebPurchasedSubscriptionInfoRepositoryImpl(
      db: sl(),
    );
  });

  sl.registerLazySingleton<WebTransactionRepository>(() {
    return WebTransactionRepositoryImpl(
      db: sl(),
    );
  });

  // services

  sl.registerLazySingleton<AccessTokenService>(() {
    return const AccessTokenServiceImpl();
  });

  sl.registerLazySingleton<EmailService>(() {
    return const EmailServiceImpl();
  });

  sl.registerLazySingleton<PasswordService>(() {
    return const PasswordServiceImpl();
  });

  // middlewares

  sl.registerLazySingleton<ForbidAdminAuthorization>(() {
    return ForbidAdminAuthorizationImpl(
      verifyAccessToken: sl(),
    );
  });

  sl.registerLazySingleton<LogRequests>(() {
    return const LogRequestsImpl();
  });

  sl.registerLazySingleton<RequireAdminAuthorization>(() {
    return RequireAdminAuthorizationImpl(
      verifyAccessToken: sl(),
    );
  });

  sl.registerLazySingleton<RequireAuthorization>(() {
    return RequireAuthorizationImpl(
      verifyAccessToken: sl(),
    );
  });

  sl.registerLazySingleton<RequireEndUserAuthorization>(() {
    return RequireEndUserAuthorizationImpl(
      verifyAccessToken: sl(),
    );
  });
}
